using System;
using Caliburn.Micro;

namespace MediaOwl.Common.Dialog
{

    public class DialogResultEventArgs : EventArgs
    {
        public Exception Error;
        public DialogResult DialogResult;
    }

    public class ShowDialog<TDialog> : IResult
        where TDialog : class, IDialog
    {
        private IDialogCapable parent;
        private IDialog dialog;

        private Func<ActionExecutionContext, IDialogCapable> locateParent;
        private Action<TDialog> onConfigure;
        private Action<TDialog> onComplete;

        private readonly Func<ActionExecutionContext, TDialog> locateDialog =
            c => IoC.Get<TDialog>();

        public ShowDialog() { }

        public ShowDialog(TDialog dialog)
        {
            locateDialog = c => dialog;
        }

        public ShowDialog<TDialog> In<TParent>()
            where TParent : IDialogCapable
        {
            locateParent = c => IoC.Get<TParent>();
            return this;
        }

        public ShowDialog<TDialog> In(IDialogCapable target)
        {
            locateParent = c => target;
            return this;
        }

        public ShowDialog<TDialog> Configured(Action<TDialog> configure)
        {
            onConfigure = configure;
            return this;
        }

        public ShowDialog<TDialog> Resulting(Action<TDialog> complete)
        {
            onComplete = complete;
            return this;
        }

        public void Execute(ActionExecutionContext context)
        {
            if (locateParent == null)
                locateParent = c => (IDialogCapable)c.Target;

            parent = locateParent(context);
            var tdialog = locateDialog(context);

            if (onConfigure != null)
                onConfigure(tdialog);

            dialog = tdialog;
            // Needs to be an IDialog so we can hook on the Completed event
            //var dialog = o as IDialog;
            if (dialog == null)
                throw new InvalidOperationException();

            if (parent == null)
            {
                Completed(this, new ResultCompletionEventArgs
                {
                    Error = new Exception("This parent screen is not of type IDialogCapable: " + context.Target),
                    WasCancelled = true,
                });
                return;
            }

            dialog.Completed += (sender, e) =>
            {
                dialog = sender as IDialog;

                if (null == dialog) throw new ArgumentException("sender");
                dialog.CanClose(a =>
                {
                    if (!a) return;
                });

                if (onComplete != null)
                    Caliburn.Micro.Execute.OnUIThread(() => onComplete(dialog as TDialog));

                Completed(this, new ResultCompletionEventArgs
                {
                    WasCancelled = false,
                    Error = e.Error
                });
            };

            parent.ShowDialog(dialog);
        }

        public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
    }
}